約 3,419,687 件
https://w.atwiki.jp/muscle-brain/pages/72.html
能力値(常時補正は省略) 外交スキル 大規模戦闘用 [部分編集] 能力値(常時補正は省略) 統 武 情 政 特殊能力(全体能力) やらない夫 20 6 4 8 内政:+10%(月2) 大規模戦闘指揮:+20% 大規模戦闘指揮:部隊上限+3 大規模戦闘指揮:全部隊兵力+15%※同系統能力と重複しない 大規模戦闘指揮:兵力+30% 外交・会話:失敗回避(月2) 大規模戦闘指揮:全単騎戦力+10% 大規模戦闘6部隊指揮:+5% 2季毎、【統率】+2 ヴィルヘルム 3 21 7 2 【武勇】判定:+20% 戦闘での【情報】判定:情報+5 小規模戦闘単独:+30% 戦闘:+15% 小規模戦闘:+20% 【武勇】が上の相手との戦闘:【武勇】を対象との平均に上昇 1月毎、戦闘での【情報】判定振り直し 大規模戦闘単独:敵3部隊から戦力判定値吸収 戦闘:+10%(~69%の時) 咲夜 8 9 9 9 産業振興:+参加人数×5% 奇数月毎、コミュ回数+1 小規模戦闘:+10% 大規模戦闘補佐:兵力+10% サブ:+5% 【政治】判定:+5% 1月毎、複数コミュ1回可 シュテル 2 14 8 5 大規模戦闘:+20% 1季毎、【武勇】+5 大規模戦闘:自兵力+100% 大規模戦闘:敵1部隊兵力-40%※この能力は妨害できない 大規模戦闘補佐:兵力+20% 2季毎、【武勇】+2 小規模戦闘:戦力値-50% チルノ 3 6 1 10 サブ-内政:+10% 4季毎、特殊能力1回分回復 ゲーム中1度、未参加判定振りなおし 4季毎、未参加判定+10% 商業振興:+10% サブ-内政:【能力値そのまま】 1季毎、ランダムイベント2つに 【政治】判定:+10% ルサルカ 4 11 10 8 サブ-内政:【判定値】+5 1月毎、戦闘・情報戦:+20% 1季毎、ランダムイベント±2 小規模戦闘:+5% 1季毎、内政行動数+1 【情報】判定勝利時、戦闘:+5% 【情報】判定:+5% ルルーシュ 13 1 9 11 農業振興:+5% 【政治】判定:+5% 大規模戦闘:兵力+20% 1季毎、大規模戦闘指揮:味方への兵力減少効果半減 大規模戦闘指揮:+15% 農業振興:生産力上昇+100 大規模戦闘補佐:+10% 射命丸 2 4 14 7 月の初めに情報収集3つ メイン-【情報】判定:+20% 情報収集:【情報】+6 1月毎、情報収集判定再転 自コミュ時100金で味方情報開示 ジェレミア 15 9 7 7 治安低下-5 大規模戦闘:兵力+30% 大規模戦闘:+10% 戦闘:+10%(~59%の時) 1季毎、【政治】判定:+15% 商業+100 二代 11 14 2 2 月初めに兵力強化(上限250) 訓練成功率+20% 武勇補佐:兵力+【武勇】の2乗 小規模戦闘:+15% 大規模戦闘補佐:兵力+10% 武勇補佐しつつ統率補佐できる 1季毎、敵デバフ能力を一つ無効化 エリー 1 8 3 10 産業振興:+20% 産業振興失敗:3/4で経済力-100 2季毎、仲間5人再行動可 4季毎、同メンバーで1枠2回の産業振興 要塞建築:+5% 要塞建築:効力+5% 工業振興:工業力上昇+100 成長毎、無料で擲弾兵に兵種転換 要塞建築:【政治】判定 ※擲弾兵:特殊兵科。一般兵からのスキルによる兵種転換でしか作れないが、維持コスト据え置き。 [部分編集] 外交スキル 名前 効果 ヴィルヘルム 威圧 相手が理不尽な(高圧的な)要求を叩きつけてきた場合、それを跳ねのける 咲夜 フォロー (小さなミスを強引に誤魔化す) シュテル 大魔力 相手が敵対的・かつ魔法系キャラの場合、『威圧』と同じ効果を2回まで得られる チルノ 純真 善良な性質に強く傾いていたり、子供好きの相手との会談に連れていくと、好印象。ただし、子供を連れていくのが不適切な会談の場合、悪印象。 ルサルカ 悪辣 相手に対して、やらない夫が提案を忘れた通し得る要求を一つ、それなりの条件で叩き付ける ルルーシュ 富裕 金銭・食糧・資材を支払う形の交渉の際、男爵領の国庫への負担を30%減らす。(最終決定値から30%減) 射命丸 対人諜報 外交相手の情報がまだ明らかになっていない場合、直前でそれをオープンする。 ジェレミア 二代 エリー [部分編集] 大規模戦闘用 統 武 情 政 兵力増加 勝率補正 ステ関連 他 やらない夫 20 6 4 8 +15%(味方全体)+30% +20%+ 5%(6部隊指揮時) 統率+2(1/2季) 部隊上限+2最終戦力+10%(味方全単騎) ヴィルヘルム 3 21 12 2 +15%+10%(~69%の時) 武勇:対格上時、対象との平均に上昇 敵3部隊から判定値10%ずつ吸収 咲夜 8 9 9 9 +10% +5% シュテル 2 14 8 5 +100%(個人)+20% +20% 武勇+5(1/1季)武勇+2(1/2季) 先制で敵1部隊兵力40%減(妨害能力無効) チルノ 3 6 1 10 未参加判定+10%(1/4季)戦闘に出すと王様に首おいてけされる ルサルカ 4 11 10 8 +20%+ 5%(情報判定で勝利) ルルーシュ 13 1 9 11 +20% +15%+10% 兵力減少効果半減(1/1季、味方全体) 射命丸 2 4 14 7 ジェレミア 15 9 7 7 +30% +10%+10%(~59%の時) 二代 11 14 2 2 +【武勇】の2乗(武勇補佐時)+10% 武勇補佐しつつ統率補佐できる敵デバフ能力を一つ無効化(1/1季) エリー 1 8 3 10 備考 赤字メインの場合のみ発動 青字サブの場合のみ発動
https://w.atwiki.jp/msa_medius/pages/10.html
最終更新 2010年10月02日 ここにはダウンロード用のファイルやSS等を掲載しようかと思っています。 「なかゆび工房」バナー #ref error :ご指定のファイルが見つかりません。ファイル名を確認して、再度指定してください。 (MF.gif)
https://w.atwiki.jp/9mens/pages/11.html
・SH#紅良太郎【えすえいち しゃーぷ くれないりょうたろう】 放送主でもあるSHS9の通り名。ゲーム"リッジレーサー6"のトップランカー。 道を間違えたのかネトラジ界に迷った 野上良太郎の声と紅渡の声を自在に操るミラクルDJである。 だが漢字に弱い。英語にも弱い。低い声にも弱い。モモタロスにも弱い。 モモタロスの角とモモタロスのソフビが18センチという言葉に過剰反応する。 俺の嫁なのでそのへん夜呂死苦。(DS談) おうどん【おうどん】 おうどん。 わっしょい放送【わっしょい ほうそう】 DSが電ラジ復活放送のことを省略しすぎてしまった。どんなお祭りだよ。 ディドゥ【でぃどぅ】 飲料メーカーDyDo(ダイドー)のことをSHはずっとディドゥだと思っていた。 後にディドゥは色んな使い方をされる。 ※超ディドゥってる ディドゥって気がするよ 等 モモタロスの角【ももたろす の つの】 詳しくは18禁なのでDSまで。ただし聞く時は覚悟が必要である。 モモタロスのソフビは18センチ【ももたろす の そふび は じゅうはち せんち】 測ってみたら18センチでした。SHくん、頑張って。 モモタロス「良太郎、やらないか」【ももたろす 「りょうたろう、やらないか」】 SHくんがいきなりチャットで打ってきた。角的な意味でらしい。 ・himasing【ひまじん】 ひまちん【ひまちん】 himasingさんの真の人格。うんこちんこで大爆笑する小学生。 16年間暇チンなので、誕生日にはぴことちこのオ7ホをみんなで買ってあげようね。
https://w.atwiki.jp/shinkenmarkmoshi/pages/4.html
2014 2013 2012 2011 2010 2009 テンプレート
https://w.atwiki.jp/kaistseries/pages/16.html
戦士 名前 クラス 年齢 通り名 武器 キルマ B→A→B 1738万歳 『スケルトン・ナイト』 マクバル・アズス
https://w.atwiki.jp/javadsge/pages/147.html
package dbx; public class pro { int creditnumber; String[] credit=new String[50]; String[] style=new String[50]; int[] strlong=new int[50]; String[][] data=new String[5000][10]; int datanumber; int number; int[] v=new int[500]; public static void main(String[] args) { pro test=new pro(); } pro(){ creditnumber=2; credit[1]="a"; credit[2]="b"; style[1]="INTEGER"; style[2]="VARCHAR"; strlong[1]=0; strlong[2]=20; String db,tab; db="dbc"; tab="dbc"; table sub=new table(); sub.credit=credit; sub.creditnumber=creditnumber; sub.style=style; sub.strlong=strlong; sub.makedata(db,tab); int s; datanumber=400; for(s=1;s 401;s++){ data[s][1]=""+s; data[s][2]="b"+s; } insert sub2=new insert(); sub2.creditnumber=creditnumber; sub2.style=style; sub2.data=data; sub2.datanumber=datanumber; sub2.makedata(db,tab); select sub3=new select(); sub3.makedata(db,tab,"b25"); number=sub3.number; v=sub3.v; System.out.println(number); System.out.println(v[1]); } } package dbx; import java.sql.*; public class table{ Connection dbx; Statement stx; String sqx; ResultSet rsx; int creditnumber; String[] credit=new String[50]; String[] style=new String[50]; int[] strlong=new int[50]; void makedata(String db,String tab){ String str; str=""; int s; for(s=1;s creditnumber;s++){ if(style[s].equals("INTEGER"))str=str+credit[s]+" "+style[s]+","; if(style[s].equals("VARCHAR"))str=str+credit[s]+" "+style[s]+"("+strlong[s]+"),"; } s=creditnumber; if(style[s].equals("INTEGER"))str=str+credit[s]+" "+style[s]; if(style[s].equals("VARCHAR"))str=str+credit[s]+" "+style[s]+"("+strlong[s]+")"; String url = "jdbc h2 "+db+";create=true"; String usr = ""; String pwd = ""; try{ Class.forName("org.h2.Driver"); dbx = DriverManager.getConnection(url, usr, pwd); stx = dbx.createStatement(); String sqx = "CREATE TABLE " +tab+"("+str+")"; stx.executeUpdate(sqx); } catch (Exception ex) { ex.printStackTrace();} } } package dbx; import java.sql.*; import java.io.*; class insert { Connection dbx; Statement stx; String sqx; ResultSet rsx; String[] style=new String[50]; int creditnumber; String[][] data=new String[5000][50]; int datanumber; int p; void makedata(String db,String tab) { String str; int s,sx; for(p=1;p datanumber+1;p++){ str=""; for(sx=1;sx creditnumber;sx++){ if(style[sx].equals("VARCHAR"))str=str+change(data[p][sx])+","; if(style[sx].equals("INTEGER"))str=str+data[p][sx]+","; } sx=creditnumber; if(style[sx].equals("VARCHAR"))str=str+change(data[p][sx]); if(style[sx].equals("INTEGER"))str=str+data[p][sx]; String url = "jdbc h2 "+db+";create=true"; String usr = ""; String pwd = ""; try{ Class.forName("org.h2.Driver"); dbx = DriverManager.getConnection(url, usr, pwd); stx = dbx.createStatement(); String sql = "INSERT INTO "+tab+" VALUES("+str+")"; int num = stx.executeUpdate(sql); stx.close(); } catch (Exception ex) { ex.printStackTrace();} } } String change(String str){ String str1; str1=" "+str+" "; return str1; } } package dbx; import java.sql.*; class select{ Connection dbx; Statement stx; String sqx; ResultSet rsx; int key; String word; int sx,number; int[] v=new int[500]; void makedata(String db,String tab,String word){ String url = "jdbc h2 "+db+";create=true"; String usr = ""; String pwd = ""; try { Class.forName("org.h2.Driver"); dbx = DriverManager.getConnection(url, usr, pwd); } catch (Exception ex) { ex.printStackTrace();} sx=0; try { stx = dbx.createStatement(); sqx="select * from "+tab+" WHERE b like "+change(word); rsx = stx.executeQuery(sqx); if (rsx != null) { while (rsx.next()) { sx=sx+1; v[sx]= rsx.getInt("a"); } } number=sx; rsx.close(); stx.close(); dbx.close(); } catch (Exception ex) {ex.printStackTrace();} } String change(String word){ String e; e=" "+word+" "; return e; } }
https://w.atwiki.jp/suokusin/pages/16.html
ここには、起こった出来事等を綴っていきます 4/24-作成
https://w.atwiki.jp/bluelily/pages/27.html
調べれば見つかるけど調べる手間を省きたい人向けデータベース 略して調省(しらしょう)データベース 命中 ヘイスト 命中 命中率と命中値は別物。自分の命中値と敵の回避値から命中率が算出されているらしい。 命中率は95%が最高値。 スキル200以上の武器を使う場合の命中値の計算方法は以下。 ①近接物理(二刀流){200+(スキル-200)*0.9+ジョブ特性+DEX/2+装備の命中}*食事補正 ②近接物理(両手持ち){200+(スキル-200)*0.9+ジョブ特性+DEX*3/4+装備の命中}*食事補正 ③遠隔物理{200+(スキル-200)*0.9+ジョブ特性+AGI/2+装備の命中}*食事補正 ある程度以上の命中値について命中値2=命中率1%になるらしい。 通常攻撃時、「ヘイスト合計+命中率 99」ならば与ダメジーの増加量は「ヘイスト+1% 命中率+1%(命中値+2)」詳細はこんな感じになる模様。この数値以下の命中値とヘイスト1%ならヘイスト1%の方が総与ダメージダメージが伸びる…はず。 WSの初段には強力な命中補正(命中値+30?)がついている。 ページTOPへ ヘイスト ここではヘイストは1000分率で表記(計算が楽だから) 装備(250)・魔法(437)・その他(上限不明)の3カテゴリーある。 魔法枠魔法ヘイスト:150 進撃マーチ:62(+2楽器付きで93) 凱旋マーチ:71(*2楽器付きで102)よく言う「20」は1024分率での数字。 凱旋マーチについてはレベル75スキルキャップ・メリポなし装備補正なしの状態 管楽器+歌唱がおおよそ+7される毎に+1される リフュエリング:100ヘイストに上書きされる。 ヘイストベルト:100魔法ヘイストと独立。 よってソウルマチマチヘイストで上限をオーバーする事になる。 その他八双:100 デスペレートブロー:50*メリポ八双とデスペは同枠扱いで上限が250 攻撃間隔実攻撃間隔=武器攻撃間隔(*二刀流係数)*(1000-ヘイスト)/1000 間60で約1秒 リキャスト実リキャスト時間=基本リキャスト時間*{1000-(ファストキャスト/2+ヘイスト)}/1000 実リキャストの50%未満にはならない。 ページTOPへ 名前 コメント すべてのコメントを見る ページTOPへ
https://w.atwiki.jp/wiki8_m2/pages/16.html
1.5 リレーショナルデータベースの主な特徴 SQL文を通し、DBへのアクセスと変更を行う。 ユーザーはデータの物理的配置を知る必要はない。 SQL文の中ではさまざまな演算子を使用できる。 データベースとアプリケーションの変更が互いに影響を及ぼさない 1.6 リレーショナルモデルの構成要素 オブジェクトあるいはリレーションの集合 リレーションを操作する演算子のセット 正確性および一貫性のためのデータ整合性 1.7 SQLの分類 SQLはリレーショナルデータベース用のデータベースアクセス言語である。 階層型データベースやネットワークデータベースのアクセス言語は別にある 【SQLの分類】 データ操作言語(DML) SELECT, INSERT, UPDATE, DELETE, MERGE データ定義言語(DDL) CREATE TABLE, TRUNCATE TABLEなど データ制御言語(DCL) GRANT, REVOKEなど トランザクション制御 COMMIT, ROLLBACK, SAVEPOINTなど 1.11 Oracleサーバーの構成 Oracleサーバー Oracleデータベース Oracleインスタンス 2.1. SGA(システムグローバル領域) 2.2. バックグラウンドプロセス
https://w.atwiki.jp/opentfc/pages/117.html
## Time-stamp 2011-12-16 Fri 14 49 08 JST 3.1 CDとレコード 3.2 CDのリファイリング 3.3 データベースの中身を見てみる 3.4 ユーザインタラクションを改善する 3.5 データベースの保存と読み出し 3.6 データベースにクエリを投げる 3.7 既存のレコードを更新する(もう1つのwhereの使い道) 3.8 ムダを排除して勝利を収める CDとレコード CDのタイトル、アーティスト名、レート、リッピング済みかなどの情報をレコードに持たせる。 ここではリストを使ったデータ構造で。 属性リスト(Property list plist)を使う。 要素を説明するシンボルとその要素が、先頭から順に交互に並んでいるリスト。 CL-USER (list a 1 b 2 c 3) ( A 1 B 2 C 3) 属性リストはgetf関数が使える。 getf関数は、属性リストとシンボルを1つずつ取り、 属性リストの中のシンボルの次にある値を返す。 ハッシュっぽいやつ。 CL-USER (getf (list a 1 b 2 c 3) a) 1 4つのフィールドを引数にとってCDを表す属性リストを返す関数make-cd (defun make-cd (title artist rating ripped) (list title title artist artist rating rating ripped ripped)) CL-USER (make-cd "Roses" "Kathy Mattea" 7 t) ( TITLE "Roses" ARTIST "Kathy Mattea" RATING 7 RIPPED T) CDのファイリング 複数のレコードを保持する。 グローバル変数*db*を使う。 グローバル変数の前後にアスタリスクをつけるのはLisp界隈のならわし。 (defvar *db* nil) 「*db*」に要素を加えるにはpushマクロが使える。 抽象化のためにadd-record関数を追加。 CL-USER (add-record (make-cd "Roses" "Kathy Mattea" 7 t)) (( TITLE "Roses" ARTIST "Kathy Mattea" RATING 7 RIPPED T)) CL-USER (add-record (make-cd "Fly" "Dixie Chicks" 8 t)) (( TITLE "Fly" ARTIST "Dixie Chicks" RATING 8 RIPPED T) ( TITLE "Roses" ARTIST "Kathy Mattea" RATING 7 RIPPED T)) pushは変更した変数の更新後の値を返す。 データベースの中身を見てみる 「*db*」を見やすくする。 データベースの内容をダンプする関数dump-db。 (defun dump-db () (dolist (cd *db*) (format t "~{~a ~10t~a~%~}~%" cd))) format関数についてはどっかでまとめる。 ユーザインタラクションを改善する add-recordでもレコードの追加はできるけど、普通のユーザにはLispくさすぎる。 また大量に登録するには向いていない。 情報の入力を促して結果を読み込む手段がいる。 (defun prompt-read (prompt) (format *query-io* "~a " prompt) (force-output *query-io*) (read-line *query-io*)) ストリーム*query-io*にpromptをフォーマットして出力。 force-outputで改行コードを待つことなくプロンプトが印字されるように保証。 テキストを1行読み込む関数read-lineで、 端末に接続された入力ストリーム*query-io*を読み込んで、 read-lineは改行文字を含まない*query-io*(文字列)を返す。 値を次々に入力してCDレコードを作るには、make-cdとprompt-readを組み合わせる (defun prompt-for-cd () (make-cd (prompt-read "Title") (prompt-read "Artist") (prompt-read "Rating") (prompt-read "Ripped [y/n] "))) prompt-readが返すのは文字列だから、文字列以外を返してほしい部分を書き換える。 parse-integer関数でRatingを数にする。 (parse-integer (prompt-read "Rating")) parse-integerはデフォルトでは、文字列に数以外が入っていたらエラーになるからオプションをつける。 オプション junk-allowedを使ってエラーにならないようにする。 エラーの代わりにnilが返ってくるが、0が返ってくるように変更する。 (or (parse-integer (prompt-read "Rating") junk-allowed t) 0) Rippedの部分は、y/nのブール値を入れるようにする。 (y-or-n-p "Ripped [y/n] ") yかnを入れないと再入力を要求する。 大量にデータを入力するためにループさせる。 loopマクロを使う。 loopマクロはreturnが呼び出されるまで繰り返し実行するもの。 (defun add-cds () (loop (add-record (prompt-for-cd)) (if (not (y-or-n-p "Another? [y/n] ")) (return)))) データベースの保存と読み出し 保存 登録したデータベースのレコードを保存する関数save-db。 ファイル名を引数に取り、現在のデータベースの状態を保存する。 (defun save-db (filename) (with-open-file (out filename direction output if-exists supersede) (with-standard-io-syntax (print *db* out)))) with-open-fileマクロはfilenameに対応するファイルをオープンし、 それに対応するストリームを変数outに束縛し、 一連の式の評価が終わったらファイルをクローズする。 途中でよくないことが起きてもクローズしてくれる。 「 direction output」で書き込みモード、 「 if-exists supersede」で同じ名前のファイルが存在したら上書きすることを指定。 ファイルを開いたら(print *db* out)で印字。 printはLispオブジェクトを再度読み取り可能な形で出力。 with-standard-io-syntaxマクロは、標準化した出力にしてくれる。(処理系の違いを気にしなくてよくなる) 読み出し データベースを読み戻すための関数load-db。 (defun load-db (filename) (with-open-file (in filename) (with-standard-io-syntax (setf *db* (read in))))) with-open-fileマクロの directionはデフォルトで inputなっている。 印字する代わりにread関数でストリームinから読み込む。 db*が上書きされるのに注意。 データベースにクエリを投げる データベースに追加したり読みだしたりする機能はつけたけど、 いちいち全部のデータベースを読み込まないといけないから、 こんな機能があったらいい。 (select artist "Dixie Chicks") これでアーティスト名がDixie Chicksになっているレコードのリストを取得する。 remove-if-not関数 CL-USER (remove-if-not # evenp (1 2 3 4 5 6 7 8 9 10)) (2 4 6 8 10) 述語とリストを引数にとって、元のリストから述語が真となる要素だけを含むリストを返す。 述語でなく、ラムダ式を渡すこともできる。 evenpという関数が無かったらなかったら、 CL-USER (remove-if-not # (lambda (x) (= 0 (mod x 2))) (1 2 3 4 5 6 7 8 9 10)) (2 4 6 8 1) アーティスト名にマッチするレコードを取り出す。 入力したアーティスト名にマッチしたら真を返す関数がいる。 レコードを表現するのに属性リストを使っているから、 getf関数が使える。 データベース内のある1つのレコードを保持する変数をcdとする。 cdの artistに対応する要素を(getf cd artist)で取る。 equal式でラムダ式で引数のartistと、cdの artistに対応する要素が等しいか見る。 (defun select-by-artist (artist) (remove-if-not # (lambda (cd) (equal artist (getf cd artist))) *db*)) アーティスト名での検索以外にもtitleとか,ratingとかでの検索が欲しくなる。 これらはラムダ式以外は同一の関数になるだろうから, 関数selectを使って一般化する。 (defun select (selector-fn) (remove-if-not selector-fn *db*)) remove-if-notに変数selector-fnに束縛されたラムダ式を渡すから「# 」はいらない。 select関数を呼び出すときに「# 」が必要。 関数selectに渡すラムダ式をラッピングする。 (defun artist-selector (artist) # (lambda (cd) (equal (getf cd artist) artist))) 関数artist-selectorはある関数を返す。 帰ってくる関数が参照してる変数は,関数artist-selectorが返った時点では 存在していないように見えるかもしれないが,ちゃんと動く。 このような関数を閉包(クロージャ)と呼ぶ。 「"Dixie Chicks"」を引数にしてartist-selectorを呼び出せば, CDの artistがDixie Chicksと同じかどうかを調べるラムダ式が得られる。 CL-USER (select (artist-selector "Dixie Chicks")) (( TITLE "Fly" ARTIST "Dixie Chicks" RATING 8 RIPPED T) ( TITLE "Home" ARTIST "Dixie Chicks" RATING 9 RIPPED T)) 他のフィールドについてもセレクタを生成する関数が必要。 似たようなセレクタ関数生成器を何度も書くのは避けたいから,汎用のセレクタ関数生成器を書く。 与えられた引数に応じて各フィールドに対応したセレクタ関数を生成したり, フィールドの組み合わせに対応したセレクタ関数を生成する関数をつくる。 そのためにキーワードパラメータという機能について学ぶ。 引数の数を固定せずに呼び出せる関数を作れる。 普通の関数 CL-USER (defun foo (a b c) (list a b c)) FOO CL-USER (foo 1 2 3) (1 2 3) キーワードパラメータを使った関数 CL-USER (defun foo ( key a b c) (list a b c)) FOO CL-USER (foo c 3 a 1 b 2) (1 2 3) CL-USER (foo a 1 c 3) (1 NIL 3) CL-USER (foo) (NIL NIL NIL) 変数a, b, cの値は対応するキーワードに続く値に束縛される。 デフォルト値はデフォルトではnilだが,これではnilをパラメータに渡したのと区別がつかない。 これを区別するためにsupplied-pパラメータを使う。 (defun foo ( key a (b 20) (c 30 c-p)) (list a b c c-p)) 上記ではbのデフォルト値は20,cのデフォルト値は30で,変数c-pがsupplied-pパラメータである。 cに値が渡されたら真,値が渡されなければ偽となる。 CL-USER (foo c 3 a 1 b 2) (1 2 3 T) CL-USER (foo a 1 c 3) (1 20 3 T) CL-USER (foo) (NIL 20 30 NIL) 汎用セレクタ関数生成器 whereという名前で作る。 CDレコードの各フィールドに対応する4つのキーワードパラメータをとり, whereが呼び出されたときに指定された全ての値と一致するCDを選び出すセレクタ関数を作り出す。 (defun where ( key title artist rating (ripped nil ripped-p)) # (lambda (cd) (and (if title (equal (getf cd title) title) t) (if artist (equal (getf cd artist) artist) t) (if rating (equal (getf cd rating) rating) t) (if ripped-p (equal (getf cd ripped) ripped) t)))) この関数はCDレコードのフィールドごとに定義された条件式のANDを返す無名関数を値として返す。 それぞれの条件式は,引数にnil以外の値が渡されていたら, その引数がCDレコードのフィールド値と一致するかどうかを値とし, そうでなければ真を返す。 対応するパラメータが渡されなければ,条件式は真となるから, 生成されるセレクタ関数はwhereに与えられたすべての引数と一致するCDだけを選び出せる。 フィールドrippedについては,「rippedの値がnilのCDを選べ」なのか, 「rippedの値は考慮しない」という意味でrippedの値を指定していないのかを区別できるようにしている。 動作例 CL-USER (select (where rating 8 ripped t)) (( TITLE "Fly" ARTIST "Dixie Chicks" RATING 8 RIPPED T)) CL-USER (select (where artist "Dixie Chicks")) (( TITLE "Fly" ARTIST "Dixie Chicks" RATING 8 RIPPED T) ( TITLE "Home" ARTIST "Dixie Chicks" RATING 9 RIPPED T)) 既存のレコードを更新する(もう一つのwhereの使い道) データベースであれば備えられている機能,レコードの更新機能を実現する。 SQLではwhere句に一致するレコードをまとめて更新するためにupdate文がある。 update文は更新したいレコードを選択するセレクタ関数と, 変更したい値をキーワード引数を使ってにして指定すればいい。 mapcar関数を使う。 mapcar関数は,あるリストに含まれる全ての要素について関数を適用した結果を集めた新しいリストを返す。 #+BEGIN_SRC common-lisp (defun update (selector-fn key title artist rating (ripped nil ripped-p)) (setf *db* (mapcar # (lambda (row) (when (funcall selector-fn row) (if title (setf (getf row title) title)) (if artist (setf (getf row artist) artist)) (if rating (setf (getf row rating) rating)) (if ripped-p (setf (getf row ripped) ripped))) row) *db*))) #+END_SRC setfは変数にだけじゃなく,「場所」に代入するのにも使えるものだと解釈しておく。 update関数でDixie Chicksのすべてのアルバムのレートを11に変える例を示す。 #+BEGIN_EXAMPLE CL-USER (update (where artist "Dixie Chicks") rating 11) #+END_EXAMPLE データベースからレコードを削除するための関数は簡単に作れる。 #+BEGIN_SRC common-lisp (defun delete-row (selector-fn) (setf *db* (remove-if selector-fn *db*))) #+END_SRC remove-if関数はremove-if-not関数の反対。 引数にとったリストから,条件式にマッチした要素を全て削除したリストを返す。 元のリストに変更を加えるわけではないため,setfで*db*に戻り値を保存している。 ムダを排除して勝利を収める マクロを使って,これまで作った関数の無駄な重複を取り除く。 無駄はwhere関数にある。 各フィールドごとに #+BEGIN_SRC (if title (equal (getf cd title) title) t) #+END_SRC のような式を評価している。 title以外のフィールドの値のチェックのときも,いちいちtitleが入っているかチェックしている。 必要以上のチェックをしている。 無駄を省くとしたら, #+BEGIN_SRC CL-USER (select (where title "Give Us a Break" ripped t)) #+END_SRC は以下のように変更できる。 #+BEGIN_SRC CL-USER (select # (lambda (cd) (and (equal (getf cd title) "Give Us a Break") (equal (getf cd ripped) t)))) #+END_SRC このラムダ式はwhereが返すものとは違うものを返す。 効率のいいセレクタ関数を返すように意図している。 これをマクロを使って書く。 マクロ マクロは式を作る式。 マクロで作られた式をREPLが評価することで結果が返る。 簡単な例をやる。 reverse関数は引数に1つのリストをとり,そのリストの順序を反転したリストを返す関数。 backwardsというマクロを定義する。 マクロの定義は,defmacroに続けて名前,パラメータリスト,本体の式からなる。 #+BEGIN_SRC CL-USER (defmacro backwards (expr) (reverse expr)) BACKWARDS CL-USER (backwards ("hello, world" t format)) hello, world NIL #+END_SRC 動作を説明する。 - REPLがbackwardsがマクロの名前であることを認識する。 - 式("hello, world" t format)は評価されずに放っておかれる。 - backwordsの中でリストはreverseに渡され (format t "hello, world") というリストがREPLに返される。 - REPLが (format t "hello, world") を評価する。 マクロの動作おいて動作効率はまったく同じになる。 マクロを使ってwhereを改良する もともとのwhereには各フィールドに対して以下の式があった。 #+BEGIN_SRC (equal (getf cd field) value) #+END_SRC フィールドと値を受け取り上記の式を返す関数を書いてみる。 式は単なるリストだから以下のようにできると思うかもしれない。 #+BEGIN_SRC ;; 間違い (defun make-comparison-expr (field value) (list equal (list getf cd field) value)) #+END_SRC これでは,equal, getf, cd, field, valueが評価される。 fieldとvalueは期待した動作であるが,equal, getf, cdは違う。 しかし,Lispはシングルクォート「 」を評価させたくないものの前につけることで, 評価をやめさせることができる。 以下のように書けば,期待した動作をする。 #+BEGIN_SRC (defun make-comparison-expr (field value) (list equal (list getf cd field) value)) #+END_SRC #+BEGIN_EXAMPLE CL-USER (make-comparison-expr rating 10) (EQUAL (GETF CD RATING) 10) CL-USER (make-comparison-expr title "Give Us a Break") (EQUAL (GETF CD TITLE) "Give Us a Break") #+END_EXAMPLE さらにいい方法 「大半は評価されたくないけど,その中から特に評価させたい式だけを選び出して評価させることができる」ような式を書く。 バッククォート「`」を式の前に置くと,その式は評価されなくなる。 バッククォートが置かれた式の中で評価させたいものには,コンマ「,」を置く。 #+BEGIN_EXAMPLE CL-USER `(+ 1 2 3) (+ 1 2 3) CL-USER `(+ 1 2 (+ 1 2)) (+ 1 2 (+ 1 2)) CL-USER `(+ 1 2 ,(+ 1 2)) (+ 1 2 3) #+END_EXAMPLE これを使って関数make-comparison-exprを書き換える #+BEGIN_SRC (defun make-comparison-expr (field value) `(equal (getf cd ,field) ,value)) #+END_SRC セレクタ関数はフィールドと値のペア1個につき比較を行う式が1つあり,それらがandで包まれている。 whereマクロに渡す引数は単一のリストとして用意することにして, それぞれのペアに対してmake-comparison-exprを呼び出した結果を集める関数を作る。 loopを使う。 #+BEGIN_SRC (defun make-comparisons-list (fields) (loop while fields collecting (make-comparison-expr (pop fields) (pop fields)))) #+END_SRC 「while fields」はfieldsに要素が残っている間はループするという意味。 1回のループで2回のpopによりfieldsから2つの要素を取り出し, それらにmake-comparison-exprを適用する。 その結果を集めて(collecting),ループが終わったときの結果として返す。 最後にmake-comparisons-listから返されるリストをANDで包んでラムダ式に入れ込めばいい。 #+BEGIN_SRC (defmacro where ( rest clauses) `# (lambda (cd) (and ,@(make-comparisons-list clauses)))) #+END_SRC 「,@」は,@以降の式と,@を囲んでいる式を結合する。 #+BEGIN_EXAMPLE CL-USER `(and ,(list 1 2 3)) (AND (1 2 3)) CL-USER `(and ,@(list 1 2 3)) (AND 1 2 3) CL-USER `(and ,@(list 1 2 3) 4) (AND 1 2 3 4) #+END_EXAMPLE 「 rest」が引数リストにあると,関数やマクロは任意個の引数を取ることができ, 引数が1つのリストにまとめられたものが restの後の名前の変数の値になる。(ここではclauses) whereを #+BEGIN_EXAMPLE (where title "Give Us a Break" ripped t) #+END_EXAMPLE と呼ぶと,clausesの値は以下となる。 #+BEGIN_EXAMPLE ( title "Give Us a Break" ripped t) #+END_EXAMPLE マクロ展開の値を確認 関数macroexpand-1を使う。 macroexpand-1にマクロ呼び出しのフォームを渡すと, 展開されたものが返る。 #+BEGIN_EXAMPLE CL-USER (macroexpand-1 (where title "Give Us a Break" ripped t)) # (LAMBDA (CD) (AND (EQUAL (GETF CD TITLE) "Give Us a Break") (EQUAL (GETF CD RIPPED) T))) T #+END_EXAMPLE